package com.isoft.c2team3service2.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.isoft.c2team3service2.bean.ResponseData;
import com.isoft.c2team3service2.dto.ArtistRegisterDTO;
import com.isoft.c2team3service2.entity.*;
import com.isoft.c2team3service2.mapper.*;
import com.isoft.c2team3service2.service.UserService;
import com.isoft.c2team3service2.util.JwtUtil;
import com.isoft.c2team3service2.util.PwdSaltUtil;

import com.isoft.c2team3service2.util.UserHolder;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.isoft.c2team3service2.util.PwdSaltUtil.validPassword;
import static com.isoft.c2team3service2.util.RedisConstants.USER_CODE_KEY;
import static com.isoft.c2team3service2.util.RedisConstants.USER_LOGIN_KEY;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ArtistMapper artistMapper;

    @Autowired
    private HeadMapper headMapper;

    @Autowired
    private  StringRedisTemplate stringRedisTemplate;

    @Autowired
    private PersonMapper personMapper;

    @Autowired
    private FileServiceImp fileServiceImp;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserRoleMapper userRoleMapper;
    //邮箱验证
    @Override
    public String repeatEmail(String email) {
        if(StrUtil.isEmpty(email)){
            return null;
        }
        QueryWrapper<User> queryWrapper=new QueryWrapper<>();
        QueryWrapper<User> email1 = queryWrapper.eq("email", email);

        User user = userMapper.selectOne(email1);
        if(user == null){
            return null;
        }else{
            return  "success";
        }
    }

    //登录
    @Override
    public ResponseData<UserDTO> login(String email, String password, HttpServletResponse response) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        // 1. 参数校验
        if (email == null || email.trim().isEmpty() || password == null || password.trim().isEmpty()) {
            log.warn("登录参数不完整：email={}, password={}", email, password);
            return new ResponseData<>(5001, "邮箱或密码不能为空", null);
        }
        String trimmedEmail = email.trim();

        // 2. 查询用户（从tb_login表）
        QueryWrapper<User> userQuery = new QueryWrapper<>();
        userQuery.eq("email", trimmedEmail);
//        userQuery.eq("id",id);
//        userQuery.eq("username",username);
        User user = userMapper.selectOne(userQuery);
        if (user == null) {
            log.warn("用户不存在：email={}", trimmedEmail);
            return new ResponseData<>(5002, "用户不存在", null);
        }

        // 3. 密码校验（使用工具类验证加密密码）
        String dbPassword = user.getPassword();
        String dbSalt = user.getSalt();
        boolean isPasswordValid = validPassword(password, dbSalt, dbPassword);
        if (!isPasswordValid) {
            log.warn("密码错误：email={}", trimmedEmail);
            return new ResponseData<>(5003, "用户密码错误，请重新输入", null);
        }

        // 4. 查询用户关联信息（从tb_person表获取昵称、用户名等）
        QueryWrapper<Person> personQuery = new QueryWrapper<>();
        personQuery.eq("email", trimmedEmail);
        Person person = personMapper.selectOne(personQuery);
        if (person == null) {
            log.error("用户关联的Person信息不存在：email={}", trimmedEmail);
            return new ResponseData<>(5004, "用户信息不完整，请联系管理员", null);
        }

        // 5. 查询用户角色（关键：用于权限校验）
        List<Role> userRoles = roleMapper.getRolesByUserId(user.getId());
        if (userRoles == null || userRoles.isEmpty()) {
            log.error("用户未分配角色：userId={}, email={}", user.getId(), trimmedEmail);
            return new ResponseData<>(5005, "用户未分配角色，无法登录", null);
        }
        // 提取角色名称（如["艺人"]）
        List<String> roleNames = userRoles.stream()
                .map(Role::getName)
                .collect(Collectors.toList());
        log.info("用户登录成功，角色列表：userId={}, email={}, roles={}",
                user.getId(), trimmedEmail, roleNames);

        // 6. 封装UserDTO（返回给前端的用户信息）
        // 修改UserDTO赋值部分的代码
        // 正确调用：第一个参数是源对象，第二个是目标类的Class，第三个是CopyOptions
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);

        userDTO.setId(user.getId());
        userDTO.setNickName(person.getNickName()); // 昵称
        userDTO.setUsername(person.getUsername()); // 用户名
        userDTO.setIsArtist(person.getIsArtist()); // 是否艺人标识
//        userDTO.setUser_id(user.getId());
        userDTO.setRoles(roleNames); // 设置角色列表
//        userDTO.setArtistId(user.getArtistId());

// 补充：如果需要，可添加其他字段的赋值
        Integer artistId = userDTO.getArtistId();
        if (artistId != null) {
            userDTO.setArtistId(user.getArtistId());
        } else {
            // 普通用户不存artistId字段，或存为null（根据业务需求选择）
            userDTO.setArtistId(0);
        }
        userDTO.setLastLoginTime(user.getLastLoginTime()); // 复制最后登录时间

// 7. 生成JWT Token（包含用户ID、邮箱、角色）
        // 7. 生成JWT Token（包含用户ID、邮箱、角色）
        String jwtToken = jwtUtil.generateToken(user.getId(), trimmedEmail, roleNames);
// 给Token添加Bearer前缀
        String tokenWithBearer = "Bearer " + jwtToken;
//        String hashKey = DigestUtils.md5DigestAsHex(jwtToken.getBytes());
        String hashKey = DigestUtils.md5DigestAsHex(jwtToken.getBytes());
        String redisKey = USER_LOGIN_KEY + jwtToken;
        log.info("生成JWT Token: {}", jwtToken);

// 8. 存储用户信息到Redis（修复存储逻辑）
        log.info("Redis存储键: {}", redisKey); // 添加日志

        try {
            // 转换UserDTO为Map存储到Redis Hash
            Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                    CopyOptions.create()
                            .setIgnoreNullValue(true)
                            .setFieldValueEditor((fieldName, fieldValue) ->
                                    fieldValue == null ? "" : fieldValue.toString()));

            // 在这里显式添加带Bearer前缀的Token到Map中
            userMap.put("token", tokenWithBearer); // 关键：将带Bearer前缀的JWT Token存入Redis

            // 打印存储的字段数量，确认转换成功
            log.info("Redis存储字段数量: {}", userMap.size());

            // 存入Redis并设置过期时间
            stringRedisTemplate.opsForHash().putAll(redisKey, userMap);

            // 后续代码保持不变...
            Long expireTime = jwtUtil.getExpiration();
            log.info("设置Redis过期时间: {} 毫秒", expireTime);
            boolean expireResult = stringRedisTemplate.expire(redisKey, expireTime, TimeUnit.MILLISECONDS);
            log.info("Redis过期时间设置结果: {}", expireResult);

            Long size = stringRedisTemplate.opsForHash().size(redisKey);
            log.info("Redis实际存储字段数量: {}", size);
            Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(redisKey);
            log.info("Redis中对应键的值: {}", entries);
        } catch (Exception e) {
            log.error("Redis存储失败", e);
        }


        // 9. 设置响应头（传递JWT Token，格式：Bearer + 空格 + Token）
        response.setHeader("Authorization", "Bearer " + jwtToken);
        // 允许前端读取响应头（解决跨域时前端无法获取Authorization头的问题）
        response.setHeader("Access-Control-Expose-Headers", "Authorization");

        // 10. 存入ThreadLocal（供当前请求的后续业务逻辑使用）
        UserHolder.saveUser(userDTO);

        // 11. 返回登录成功结果
        return new ResponseData<>(200, "登录成功", userDTO);
    }

    //修改密码
    @Override
    public boolean updatePassword(String email, String password) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        if(email == null){
            return false;
        }
        if(password == null||password.isEmpty()){
            return false;
        }

        String salt = PwdSaltUtil.getSalt();
        String encryptedPassword = PwdSaltUtil.getEncryptedPwd(password, salt);

        return userMapper.updatePassword(email, encryptedPassword , salt)>0;
    }

    //注册
    @Override
    @Transactional
    public Map<String, Object> register(String email, String code, String password , Integer roleId) {
        Map<String, Object> result = new HashMap<>();

        String s = stringRedisTemplate.opsForValue().get(USER_CODE_KEY + email);

        // 验证码是否过期
        if (s == null) {
            result.put("fail", false);
            result.put("message", "验证码已过期，请重新获取");
            return result;
        }

        // 验证验证码是否正确
        if (!s.equals(code)) {
            result.put("success", false);
            result.put("message", "验证码错误");
            return result;
        }

        // 验证通过，执行注册逻辑（如保存用户到数据库）
        try {
            addUser(email,password,roleId);// 示例：调用用户服务注册

            result.put("success", true);
            result.put("message", "注册成功");
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "注册失败：" + e.getMessage());
        } finally {
            stringRedisTemplate.delete(USER_CODE_KEY + email);
        }

        return result;
    }

    @Override
    public String findBackgroundByEmail(String email) {
        QueryWrapper<Person> personQueryWrapper = new QueryWrapper<>();
        personQueryWrapper.eq("email", email);
        return personMapper.selectOne(personQueryWrapper).getBackground();
    }

    /**
     * 艺人注册核心逻辑（事务保证三表一致性）
     */
    @Override
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class}) // 事务注解：任一表插入失败则回滚
    public Map<String, Object> artistRegister(ArtistRegisterDTO dto) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        Map<String, Object> result = new HashMap<>();
        // 1. 统一处理邮箱：与EmailServiceImp一致（trim+toLowerCase）
        String processedEmail = dto.getEmail().trim();
        String clientCode = dto.getCode(); // 客户端传递的验证码
        String redisKey = USER_CODE_KEY + processedEmail;

        // 2. 打印调试日志：便于对比客户端code和Redis code
        log.info("艺人注册验证码校验：processedEmail={}, 客户端code={}, Redis键={}",
                processedEmail, clientCode, redisKey);

        // 3. 验证码校验
        String redisCode = stringRedisTemplate.opsForValue().get(redisKey);
        if (redisCode == null) {
            result.put("success", false);
            result.put("message", "验证码已过期，请重新获取");
            return result;
        }
        // 注意：若客户端传递的code有空格，也需trim（避免用户输入时误加空格）
        if (!redisCode.equals(clientCode.trim())) {
            log.error("验证码不匹配：Redis code={}, 客户端code（trim后）={}", redisCode, clientCode.trim());
            result.put("success", false);
            result.put("message", "验证码错误");
            return result;
        }

        // 4. 校验邮箱是否已注册（复用repeatEmail逻辑）
        QueryWrapper<User> userQuery = new QueryWrapper<>();
        userQuery.eq("email", processedEmail);
        if (userMapper.selectOne(userQuery) != null) {
            result.put("success", false);
            result.put("message", "该邮箱已被注册");
            return result;
        }

        // 5. 生成密码盐值并加密密码
        String salt = PwdSaltUtil.getSalt();
        String encryptedPassword = PwdSaltUtil.getEncryptedPwd(dto.getPassword(), salt);

        // 6. 插入tb_login表（User）：用户类型设为1（艺人）
        User user = new User();
        user.setEmail(processedEmail);
        user.setPassword(encryptedPassword);
        user.setSalt(salt);
        user.setUserType(1); // 关键：艺人标识
        int userInsert = userMapper.insert(user);
        if (userInsert <= 0) {
            throw new RuntimeException("用户表插入失败");
        }
        Integer userId = user.getId(); // 获取自增的用户ID

        // 7. 插入tb_person表（Person）：isArtist设为"1"
        Person person = new Person();
        person.setUsername(dto.getUsername());
        person.setNickName(dto.getNickName());
        person.setBirthdate(dto.getBirthdate());
        person.setPhonenumber(dto.getPhonenumber());
        person.setEmail(processedEmail);
        person.setIsArtist("1"); // 标识为艺人
        person.setBackground("default_background.png"); // 默认背景图
        int personInsert = personMapper.insert(person);
        if (personInsert <= 0) {
            throw new RuntimeException("会员表插入失败");
        }

        // 8. 插入artist表（Artist）：关联用户ID
        Artist artist = new Artist();
        artist.setName(dto.getArtistName());
        artist.setBirthDate(dto.getArtistBirthDate());
        artist.setGender(dto.getGender());
        artist.setNationality(dto.getNationality());
        artist.setAchievements(dto.getAchievements());
        artist.setWorks(dto.getWorks());
        artist.setUserId(userId); // 关联tb_login的user.id
        int artistInsert = artistMapper.insert(artist);  // 使用artistMapper
        if (artistInsert <= 0) {
            throw new RuntimeException("艺人表插入失败");
        }

        // 9. 更新User表的artistId（关联艺人ID）
        user.setArtistId(artist.getId());
        userMapper.updateById(user);

        // 10. 注册成功：删除Redis验证码，返回结果
        stringRedisTemplate.delete(USER_CODE_KEY + processedEmail);
        result.put("success", true);
        result.put("message", "艺人注册成功");
        result.put("email", processedEmail);
        result.put("userType", 1); // 告知前端是艺人用户

        return result;
    }

    @Override
    public String upLodeId(Integer userId) {
        return "";
    }

    //上传头像
    @Override
    public String upLode(String email) {
        if (email == null || email.isEmpty()) {
            return null;
        }
        return headMapper.upLode(email);
    }

    //上传背景图
    @Override
    public String upload(MultipartFile file) {
        UserDTO user = UserHolder.getUser();
        Integer id = user.getId();
        return fileServiceImp.background("background",file,id);
    }

    @Transactional
    public boolean addUser(String email, String password , Integer roleId) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        if(email == null||password == null){
            return false;
        }

        String salt = PwdSaltUtil.getSalt();
        String encryptedPassword = PwdSaltUtil.getEncryptedPwd(password, salt);

        int i = userMapper.addUser(email, encryptedPassword, salt, roleId);
        if(i > 0) {
            int b = userMapper.selectId(email);
            UserRole userRole = new UserRole();
            userRole.setRoleId(roleId);
            userRole.setUserId(b);
            int insert = userRoleMapper.insert(userRole);
            if (insert > 0) {
                return true;
            }
        }
        return false;
    }

}
